home *** CD-ROM | disk | FTP | other *** search
/ Your Choice 3 / Your Choice Software Collection 3.iso / os2 / blanker4 / bssdev / bounce.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-10  |  8.1 KB  |  271 lines

  1. /***************************************************************************\
  2. * BOUNCE.C - An example Desktop Screen Saver extension by John Ridges
  3. *            Converted to a 32-Bit Screen Blanker module by Peter Wansch
  4. \***************************************************************************/
  5.  
  6. #define MAXBITMAPS 25   /* How many happy faces can be on the screen */
  7.  
  8. #define INCL_DOSMEMMGR
  9. #define INCL_DOSPROCESS
  10. #define INCL_GPIBITMAPS
  11. #define INCL_WINBUTTONS
  12. #define INCL_WINDIALOGS
  13. #define INCL_WINENTRYFIELDS
  14. #define INCL_WININPUT
  15. #define INCL_WINMESSAGEMGR
  16. #define INCL_WINTIMER
  17. #define INCL_WINWINDOWMGR
  18. #define INCL_WINSHELLDATA
  19.  
  20. #include <os2.h>
  21. #include <stdlib.h>   /* Needed because SRAND and RAND are called */
  22.  
  23. typedef struct {
  24.   HAB habBlanker;
  25.   HWND hwndScreen;
  26.   RECTL rclScreen;
  27.   BOOL fClose;
  28.   HMODULE hmodBlanker;
  29. } BLANKERBLOCK;
  30.  
  31. typedef BLANKERBLOCK *PBLANKERBLOCK;
  32.  
  33. PCHAR pchStatus(PBLANKERBLOCK, PBOOL);
  34. MRESULT EXPENTRY dpBlanker(HWND, ULONG, MPARAM, MPARAM);
  35. VOID vdBlankerThread(VOID);
  36.  
  37. static PBLANKERBLOCK pBlankerBlock;
  38.  
  39. /*
  40.    This is the record that describes the position and velocity of
  41.    a happy face
  42. */
  43.  
  44. typedef struct {
  45.   FIXED xvelocity,yvelocity;
  46.   FIXED xposition,yposition;
  47. } BITMAPREC;
  48.  
  49. /*
  50.   This is the record that contains the options of the screen saver.
  51.   These options are kept in the OS2.INI profile file.
  52. */
  53.  
  54. typedef struct {
  55.   BOOL enabled;   /* The screen saver enabled status */
  56.   int numbitmaps;   /* The number of happy faces on the screen */
  57. } PROFILEREC;
  58.  
  59. static char name[] = "Bounce";  /* The name of this screen saver */
  60. static BOOL gotprofile = FALSE;  /* Indicates that we've read the profile */
  61. static PROFILEREC profile = {TRUE, 4};   /* Default values */
  62.  
  63. PCHAR pchStatus(PBLANKERBLOCK initptr, PBOOL enabledptr)
  64. {
  65.   ULONG i;
  66.  
  67.   /* Save the SAVERBLOCK address locally */
  68.   pBlankerBlock = initptr;
  69.  
  70.   /* Read the profile (but only once!) */
  71.   if (!gotprofile) {
  72.     i = sizeof(PROFILEREC);
  73.     PrfQueryProfileData(HINI_PROFILE,"Blanker",name,&profile,&i);
  74.     gotprofile = TRUE;
  75.   }
  76.   /* Return the enabled status */
  77.   *enabledptr = profile.enabled;
  78.  
  79.   /* Return the screen saver name */
  80.   return name;
  81. }
  82.  
  83. MRESULT EXPENTRY dpBlanker(HWND hwnd, ULONG message, MPARAM mp1, MPARAM mp2)
  84. {
  85.   SHORT i;
  86.  
  87.   switch(message) {
  88.   case WM_INITDLG:
  89.     /* Check the enabled button if enabled */
  90.     if (profile.enabled)
  91.       WinSendDlgItemMsg(hwnd,3,BM_SETCHECK,MPFROMSHORT(1),0);
  92.  
  93.     /* Set the Quantity field */
  94.     WinSetDlgItemShort(hwnd,4,profile.numbitmaps,TRUE);
  95.  
  96.     /* Bring up the dialog */
  97.     WinShowWindow(hwnd,TRUE);
  98.     return FALSE;
  99.  
  100.   case WM_COMMAND:
  101.     /* If OK is pushed */
  102.     if (SHORT1FROMMP(mp1) == 1) {
  103.       /* Get the value of the Quantity field */
  104.       WinQueryDlgItemShort(hwnd,4,&i,TRUE);
  105.  
  106.       /* Check to see if the Quantity is in bounds */
  107.       if (i < 1 || i > MAXBITMAPS) {
  108.         /* Bring up an error message box */
  109.         WinMessageBox(HWND_DESKTOP,hwnd,"The number of happy faces must "
  110.           "be between 1 and 25",NULL,0,MB_OK|MB_ICONHAND);
  111.  
  112.         /* Hilight the Quantity field */
  113.         WinSendDlgItemMsg(hwnd,4,EM_SETSEL,MPFROM2SHORT(0,
  114.           WinQueryDlgItemTextLength(hwnd,4)),0);
  115.  
  116.         /* Give the Quantity field the focus */
  117.         WinSetFocus(HWND_DESKTOP,WinWindowFromID(hwnd,4));
  118.  
  119.         /* Don't exit the dialog */
  120.         return FALSE;
  121.       }
  122.       /* Save the number of happy faces */
  123.       profile.numbitmaps = i;
  124.  
  125.       /* Get the enabled status */
  126.       profile.enabled =
  127.         SHORT1FROMMR(WinSendDlgItemMsg(hwnd,3,BM_QUERYCHECK,0,0));
  128.  
  129.       /* Write the profile data */
  130.       PrfWriteProfileData(HINI_PROFILE,"Blanker",name,&profile,
  131.         sizeof(PROFILEREC));
  132.     }
  133.   }
  134.   return WinDefDlgProc(hwnd,message,mp1,mp2);
  135. }
  136.  
  137. VOID vdBlankerThread(VOID)
  138. {
  139.   HAB hab;
  140.   HPS hps;
  141.   int i;
  142.   FIXED tempx,tempy;
  143.   ULONG sqrt;
  144.   POINTL aptl[4];
  145.   BITMAPREC *bitmaps;
  146.   HBITMAP hbmp;
  147.  
  148.   /* Get an HAB for this thread (since we make PM calls) */
  149.   hab = WinInitialize(0);
  150.  
  151.   /* Get an HPS of the screen */
  152.   hps = WinGetPS(pBlankerBlock->hwndScreen);
  153.  
  154.   /* Paint the screen black */
  155.   WinFillRect(hps,&pBlankerBlock->rclScreen,CLR_BLACK);
  156.  
  157.   /* Get memory for the array of BITMAPRECs */
  158.         bitmaps = NULL;
  159.         DosAllocMem((PPVOID)&bitmaps, sizeof(BITMAPREC)*profile.numbitmaps, PAG_READ | PAG_WRITE | PAG_COMMIT);
  160.  
  161.   /* Flag all the happy faces as 'position unknown' */
  162.   for (i = 0; i < profile.numbitmaps; i++) 
  163.           bitmaps[i].xposition = -1L;
  164.  
  165.   /* Get the handle to the happy face and its dimensions */
  166.   hbmp = GpiLoadBitmap(hps,pBlankerBlock->hmodBlanker,1,0L,0L);
  167.   aptl[2].x = aptl[2].y = 0;
  168.   aptl[3].x = aptl[3].y = 34;
  169.  
  170.   /* Randomize RAND using the time */
  171.   srand((unsigned int)WinGetCurrentTime(hab));
  172.  
  173.   /* Loop until Screen Blanker tells us to stop */
  174.   while (!pBlankerBlock->fClose)
  175.  
  176.     /* Process for each happy face */
  177.     for (i = 0; i < profile.numbitmaps; i++) {
  178.  
  179.     /* If the happy face's position is unknown, initialize it */
  180.     if (bitmaps[i].xposition < 0) {
  181.  
  182.       /* Pick a random x velocity between -1 and 1 (fixed) */
  183.       tempx = (long)rand()<<1;
  184.       bitmaps[i].xvelocity = rand()&1 ? tempx : -tempx;
  185.  
  186.       /*
  187.         Make the total velocity 1 by computing:
  188.         yvelocity = sqrt(1 - xvelocity * xvelocity)
  189.       */
  190.       tempy = MAKEFIXED(0,65535)-((ULONG)tempx*(ULONG)tempx>>16);
  191.  
  192.       /* Cheesy sqrt routine to avoid linking in floating point */
  193.       sqrt = 0;
  194.       tempx = 1L<<15;
  195.       do {
  196.         sqrt ^= tempx;
  197.         if (sqrt*sqrt>>16 > (ULONG)tempy) sqrt ^= tempx;
  198.         tempx >>= 1;
  199.       } while (tempx);
  200.  
  201.       /* Randomly set y velocity sign */
  202.       bitmaps[i].yvelocity = rand()&1 ? sqrt : -sqrt;
  203.  
  204.       /* Randomly choose the x and y position of the happy face */
  205.       tempx = MAKEFIXED(pBlankerBlock->rclScreen.xLeft,0)+(rand()*
  206.         (pBlankerBlock->rclScreen.xRight-pBlankerBlock->rclScreen.xLeft-32)<<1);
  207.       tempy = MAKEFIXED(pBlankerBlock->rclScreen.yBottom,0)+(rand()*
  208.         (pBlankerBlock->rclScreen.yTop-pBlankerBlock->rclScreen.yBottom-32)<<1);
  209.     }
  210.     else {
  211.       /* Find the new position of the happy face */
  212.       tempx = bitmaps[i].xposition+bitmaps[i].xvelocity;
  213.       tempy = bitmaps[i].yposition+bitmaps[i].yvelocity;
  214.  
  215.       /* See if the happy face has hit an edge of the screen */
  216.       if (FIXEDINT(tempx) < (int)pBlankerBlock->rclScreen.xLeft) {
  217.  
  218.         /* Bounced off the left edge */
  219.         tempx = (pBlankerBlock->rclScreen.xLeft<<17)-tempx;
  220.         bitmaps[i].xvelocity = -bitmaps[i].xvelocity;
  221.       }
  222.       else if (FIXEDINT(tempx) >= (int)pBlankerBlock->rclScreen.xRight-32) {
  223.  
  224.         /* Bounced off the right edge */
  225.         tempx = (pBlankerBlock->rclScreen.xRight-32<<17)-tempx;
  226.         bitmaps[i].xvelocity = -bitmaps[i].xvelocity;
  227.       }
  228.       if (FIXEDINT(tempy) < (int)pBlankerBlock->rclScreen.yBottom) {
  229.  
  230.         /* Bounced off the bottom edge */
  231.         tempy = (pBlankerBlock->rclScreen.yBottom<<17)-tempy;
  232.         bitmaps[i].yvelocity = -bitmaps[i].yvelocity;
  233.       }
  234.       else if (FIXEDINT(tempy) >= (int)pBlankerBlock->rclScreen.yTop-32) {
  235.  
  236.         /* Bounced off the top edge */
  237.         tempy = (pBlankerBlock->rclScreen.yTop-32<<17)-tempy;
  238.         bitmaps[i].yvelocity = -bitmaps[i].yvelocity;
  239.       }
  240.     }
  241.     /* Draw the happy face in the new position */
  242.     aptl[0].x = FIXEDINT(tempx)-1;
  243.     aptl[0].y = FIXEDINT(tempy)-1;
  244.     aptl[1].x = FIXEDINT(tempx)+32;
  245.     aptl[1].y = FIXEDINT(tempy)+32;
  246.     GpiWCBitBlt(hps,hbmp,4L,aptl,ROP_SRCCOPY,BBO_IGNORE);
  247.  
  248.     /* Save the position of the happy face */
  249.     bitmaps[i].xposition = tempx;
  250.     bitmaps[i].yposition = tempy;
  251.   }
  252.   /* Release the happy face bitmap */
  253.   GpiDeleteBitmap(hbmp);
  254.  
  255.   /* Release the memory for the array of BITMAPRECs */
  256.   DosFreeMem(bitmaps);
  257.  
  258.   /* Release the HPS of the screen */
  259.   WinReleasePS(hps);
  260.  
  261.   /* Get rid of the HAB */
  262.   WinTerminate(hab);
  263.  
  264.   /* Make sure the stack doesn't vanish before we're completely gone */
  265.   DosEnterCritSec();
  266.  
  267.   /* Tell Screen Blanker that we're gone */
  268.  
  269.   pBlankerBlock->fClose = FALSE;
  270. }
  271.